package claseMarcadorBowling;

/**
 * Marcador de puntos obtenidos por jugador de Bowling.
 * 
 * Responsable de calcular la puntuación obtenida por un jugador de Bowling a
 * partir de la cantidad de pinos tirados en cada una de sus chances.
 */

public class MarcadorDeBowling {
	private String jugador;
	private int[][] puntos = new int[10][];
	private int ronda = 0;
	private int tirosTotalesRonda = 0;
	
	/**
	 * @post Inicializa el marcador del jugador indicado.
	 */
	public MarcadorDeBowling(String jugador) {
		this.jugador = jugador;
		this.generarTableroPuntajes();
	}
	
	/**
	 * @post Devuelve el nombre del jugador al que pertence.
	 */
	public String getJugador() {
		return this.jugador;
	}
	
	/**
	 * @pre  El jugador puede realizar un tiro, porque el juego no ha terminado.
	 * @post Actualiza el estado del marcador a partir de la cantidad de pinos
	 *       tirados.
	 */
	public void tirar(int pinos) {
		/*
		 * Si el partido no termino se ejecuta el tiro y se guarda el puntaje realizado. 
		 * */
		if(!this.terminoPartido()){
			this.calcularPuntos(pinos);
		}
	}
	
	/**
	 * @post Comprueba si el partido termino o no.
           En caso de poder seguir jugando devuelve false.
           Si el partido termino devuelve true.
	 */
	private boolean terminoPartido(){
		boolean terminoPartido = false;
		if(this.ronda > 10){
			terminoPartido = true;
		}
		return terminoPartido;
	}
	
	/**
	 * @post Devuelve la cantidad de puntos conseguidos hasta el momento por el
	 *       jugador.
	 */
	public int getPuntos() {
		int puntosTotales = 0;
		for(int rondasJugadas = 0; rondasJugadas < this.puntos.length; rondasJugadas++){
			for(int tirosPorRonda = 0; tirosPorRonda < (this.puntos[rondasJugadas].length - 1); tirosPorRonda++){
				/*
				 * Sumo los puntos de los tiros que no fueron Strike o Semi pleno.
				 * */
				if((this.puntos[rondasJugadas][2] == 0) || (rondasJugadas == 9)){
					puntosTotales = puntosTotales + this.puntos[rondasJugadas][tirosPorRonda];
				}else{
					/*
					 * Sumo los puntos hechos por Strike o Semi pleno.
					 * */
					puntosTotales = puntosTotales + this.puntos[rondasJugadas][2];
					tirosPorRonda = this.puntos[rondasJugadas].length;
				}
			}
		}
		return puntosTotales;
	}
	
	/**
	 * @post: Calcula los puntos que se deben anotar en el tablero segun la 
	 * 		  cantidad de pinos tirados.
	 * */
	private void calcularPuntos(int pinos){
		/*
		 * Guardo los pinos tirados si el jugador no hizo un strike.
		 * */
		if(pinos != 10){
			this.puntos[this.ronda][this.tirosTotalesRonda] = pinos;
			this.tirosTotalesRonda++;
		}
		
		/*
		 * Guardo los puntos parciales hechos por strike.
		 * */
		if(pinos == 10){
			this.puntos[this.ronda][this.tirosTotalesRonda] = pinos;
			if(this.ronda != 9){
				this.tirosTotalesRonda = 2;
			}else{
				this.tirosTotalesRonda++;
			}
		}
		
		/* 
		 * A partir de la tercer ronda de tiros actualizo los puntos de los strike
		 * hechos hasta el momento.
		 * */
		if(this.ronda >= 2){
			this.actualizarPuntosPorStrike();
		}
		/*
		 * Actualizo los puntos de las rondas en donde el jugador hizo un pleno
		 * */
		if(this.ronda >= 1){
			this.actualizarPuntosPorPleno();
		}
		/*
		 * Actualizo el estado del partido(tiros y rondas restantes).
		 * En caso de estar en la última ronda checkeo si el jugador puede realizar
		 * el tercer tiro de la ronda.
		 * */
		if((this.ronda != 9) || ((this.ronda == 9 && !this.ultimoTiroDeRondaDiez()))){
			this.actualizarEstadoPartido();
		}
	}
	
	/**
	 * @post Me devuelve true en caso de que el jugado deba tirar el último de la ronda
	 * 		 número 10. Caso contrario me devuelve false.
	 * */
	private boolean ultimoTiroDeRondaDiez(){
		boolean puedeTirarTercerTiro = false;
		if(this.ronda == 9){
			/*
			 * Si el jugador realiza un Semipleno con los dos lanzamientos de la ronda
			 * número diez podra realizar el tiro extra.
			 * */
			if(this.puntos[9][0] + this.puntos[9][1] == 10){
				puedeTirarTercerTiro = true;
			}else
				/*
				 * Si el jugador realizo Strike en los dos tiros de la ronda numero 10 
				 * el jugador podra realizar el tiro extra.
				 * */
				if(this.puntos[9][0] + this.puntos[9][1] == 20){
				puedeTirarTercerTiro = true;
			}
		}
		return puedeTirarTercerTiro;
	}
	/**
	 * @post Si el jugador tira su segundo tiro o hace un Strike se pasa a la siguiente
	 * 		 ronda y se actualiza la cantidad de tiros restantes.
	 */
	private void actualizarEstadoPartido(){
		if(this.tirosTotalesRonda >= 2){
			this.ronda++;
			this.tirosTotalesRonda = 0;
		}
	}
	
	/**
	 * @post Inicializo el tablero
	 * */
	private void generarTableroPuntajes(){
		for(int i = 0; i < (this.puntos.length - 1); i++){
			this.puntos [i] = new int [3];
		}
		this.puntos [9] = new int [4];
	}
	
	/**
	 * @post Actualiza los puntos hechos por Strike
	 */
	private void actualizarPuntosPorStrike(){
		int puntosPorStrike = 0;
		/*
		 * Si hice un Strike dos rondas antes de la actual actualizo el puntaje total del Strike.
		 * */
		if((this.puntos[this.ronda- 2][0] == 10) && (this.tirosTotalesRonda >= 2)){
			/*
			 * Sumo el puntaje total si hice un Strike en el tiro anterior al actual.
			 * */
			if(this.puntos[this.ronda - 1][0] == 10){
				puntosPorStrike = 10 + this.puntos[this.ronda][0] + this.puntos[this.ronda - 1][0];
			}
			else{
				/*
				 * Sumo el puntaje parcial de los Strike
				 * */
				puntosPorStrike = 10 + this.puntos[this.ronda - 1][0] + this.puntos[this.ronda - 1][1];
			}
			/*
			 * Guardo los puntos totales del Strike.
			 * */
			this.puntos[this.ronda - 2][2] = puntosPorStrike;
		}
		/*
		 * Sumo el puntaje total si en el tiro realizado despues al Strike no se tiraron todos
		 * los pinos.(Strike doble). 
		 * */
		if((this.puntos[this.ronda- 1][0] == 10) && (this.tirosTotalesRonda >= 2)){
			puntosPorStrike = 10 + this.puntos[this.ronda][0] + this.puntos[this.ronda][1];
			/*
			 * Guardo los puntos totales del Strike.
			 * */
			this.puntos[this.ronda - 1][2] = puntosPorStrike;
		}
		/*
		 * Sumo el puntaje total del Strike realizado en la ronda 9. 
		 * */
		if((this.ronda == 9) && (this.puntos[this.ronda - 1][0] == 10) && (this.tirosTotalesRonda >= 2)){
			puntosPorStrike = 10 + this.puntos[this.ronda][0] + this.puntos[this.ronda][1];
   			this.puntos[this.ronda - 1][2] = puntosPorStrike;
		}
	}
	
	/**
	 * @post Actualiza los puntos hechos por un Semipleno(Spare)
	 * */
	private void actualizarPuntosPorPleno(){
		int puntosPorSpare = 0;
		/*
		 * Si el jugador realizo un Semipleno en la ronda anterior le sumo la cantidad de pinos tirados en el
		 * tiro actual.
		 * */
		if(((this.puntos[this.ronda - 1][0] + this.puntos[this.ronda - 1][1]) == 10) && 
			(this.puntos[this.ronda - 1][0] != 10)){
			puntosPorSpare = this.puntos[this.ronda - 1][0] + this.puntos[this.ronda - 1][1]
			               + this.puntos[this.ronda][0];
			/*
			 * Guardo el puntaje total hecho por un SemiPleno o Spare
			 * */
			this.puntos[this.ronda - 1][2] = puntosPorSpare;
		}
	}
}